﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace Exentials.Xoox.Spreadsheet
{
    [DebuggerDisplay("{_value}")]
    public class Formula
    {
        internal class FormulaCollection : Collection<Formula>
        {
            public override string ToString()
            {
                return string.Join(",", this.Select(t => t.ToString()).ToArray());
            }
        }

        private object _value;
        private string _formatExpression;

        internal Formula()
        {
        }

        internal Formula(object value)
            : this("{0}", value)
        {
        }

        public Formula(string formatExpression, object value)
        {
            this._value = value;
            this._formatExpression = formatExpression;
        }

        internal Formula(string formatExpression, params object[] values)
        {
            this._value = values;
            this._formatExpression = formatExpression;
        }

        public bool IsNull
        {
            get { return (this._value == null) || (this._formatExpression == null); }
        }

        public override string ToString()
        {
            if (this._value is Array)
                return string.Format(System.Globalization.CultureInfo.InvariantCulture, this._formatExpression, (object[])this._value);
            else
                return string.Format(System.Globalization.CultureInfo.InvariantCulture, this._formatExpression, this._value);
        }

        public static Formula Get
        {
            get
            {
                return new Formula();
            }
        }

        public static implicit operator Formula(string expression)
        {
            return new Formula(expression);
        }

        public static implicit operator Formula(int value)
        {
            return new Formula(Convert.ToString(value, NumberFormatInfo.InvariantInfo));
        }

        public static implicit operator Formula(decimal value)
        {
            return new Formula(Convert.ToString(value, NumberFormatInfo.InvariantInfo));
        }

        public static implicit operator Formula(double value)
        {
            return new Formula(Convert.ToString(value, NumberFormatInfo.InvariantInfo));
        }

        public static implicit operator Formula(XCell value)
        {
            return new Formula(value.Reference);
        }

        public static Formula operator +(Formula expression1, Formula expression2)
        {
            return new Formula("({0}+{1})", expression1, expression2);
        }

        public static Formula operator -(Formula expression1, Formula expression2)
        {
            return new Formula("({0}-{1})", expression1, expression2);
        }

        public static Formula operator *(Formula expression1, Formula expression2)
        {
            return new Formula("({0}*{1})", expression1, expression2);
        }

        public static Formula operator /(Formula expression1, Formula expression2)
        {
            return new Formula("({0}/{1})", expression1, expression2);
        }

        public static Formula operator >(Formula expression1, Formula expression2)
        {
            return new Formula("({0}>{1})", expression1, expression2);
        }

        public static Formula operator >=(Formula expression1, Formula expression2)
        {
            return new Formula("({0}>={1})", expression1, expression2);
        }

        public static Formula operator <(Formula expression1, Formula expression2)
        {
            return new Formula("({0}<{1})", expression1, expression2);
        }

        public static Formula operator <=(Formula expression1, Formula expression2)
        {
            return new Formula("({0}<={1})", expression1, expression2);
        }
    }
}
